﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using mkv16;
using System.Threading;

namespace MemoryBrowserUtility
{
    public partial class MainForm : Form
    {
        public enum SearchCollections { Notions, Words, Triples, Facts }

        public MainForm()
        {
            InitializeComponent();

            var comboValue = SearchCollections.Notions;
            comboSearchCollection.DataSource = System.Enum.GetValues(comboValue.GetType());

            workingLabelStatus.Text = "Application started";
            workingStatus.Visible = false;
            workingLabelProgress.Visible = false;

            loadingTimer = new System.Windows.Forms.Timer();
            loadingTimer.Tick += new EventHandler(loadingTimer_Tick);

            searchUpdateTimer = new System.Windows.Forms.Timer();
            searchUpdateTimer.Tick += new EventHandler(searchUpdateTimer_Tick);

            activeSearchString = String.Empty;
            loadedMemory = new MemoryStore();
        }

        private MemoryStore loadedMemory;
        private List<Notion> searchCollection;
        private List<Notion> searchResults;
        private System.Windows.Forms.Timer loadingTimer;
        private System.Windows.Forms.Timer searchUpdateTimer;
        private string activeSearchString;

        private void action_Exit(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void action_Open(object sender, EventArgs e)
        {
            var result = openMemoryFileDialog.ShowDialog();
            string memoryFile;

            if (result == DialogResult.OK)
            {
                memoryFile = openMemoryFileDialog.FileName;

                OpenFile(memoryFile);
            }
        }

        private void action_SearchFilter(object sender, EventArgs e)
        {
            var filterString = textboxSearchField.Text;

            activeSearchString = filterString;

            searchUpdateTimer.Stop();
            searchUpdateTimer.Interval = 400;
            searchUpdateTimer.Start();
        }

        private void action_CollectionFilter(object sender, EventArgs e)
        {
            filterResults();
        }

        void searchUpdateTimer_Tick(object sender, EventArgs e)
        {
            searchUpdateTimer.Stop();

            filterResults();
        }

        private void filterResults()
        {
            var filter = activeSearchString;

            if (loadedMemory == null)
                return;

            var collectionType = (SearchCollections)comboSearchCollection.SelectedValue;

            if (collectionType == SearchCollections.Facts)
            {
                searchCollection = new List<Notion>();
                foreach (var item in loadedMemory.Facts)
                    searchCollection.Add(item);
            }
            else if (collectionType == SearchCollections.Notions)
            {
                searchCollection = loadedMemory.Notions;
            }
            else if (collectionType == SearchCollections.Triples)
            {
                searchCollection = new List<Notion>();
                foreach (var item in loadedMemory.Triples)
                    searchCollection.Add(item);
            }
            else if (collectionType == SearchCollections.Words)
            {
                searchCollection = new List<Notion>();
                foreach (var item in loadedMemory.Words)
                    searchCollection.Add(item);
            }
            else
            {
                throw new Exception(String.Format("Unsupported collection type: {0}", collectionType));
            }

            searchResults = new List<Notion>();
            foreach (var item in searchCollection)
            {
                if (item.Name.Contains(filter))
                {
                    searchResults.Add(item);
                }
            }

            create_ListItems();
        }

        private void create_ListItems()
        {
            resultsList.Clear();

            // Create columns
            resultsList.Columns.Add("Name", 300);
            resultsList.Columns.Add("Context", 200);
            resultsList.Columns.Add("Source", 150);
            resultsList.Columns.Add("Type", 100);
            resultsList.Columns.Add("Timestamp", 100);

            resultsList.View = View.Details;

            // Create the list items
            ListViewItem listItem;
            Notion notionItem;

            var displayCount = 0;
            var displayLimit = 100;

            var type = "";
            var timestamp = "";

            foreach (var item in searchResults)
            {
                notionItem = item;

                listItem = new ListViewItem(notionItem.Name);
                listItem.SubItems.Add(notionItem.Source.Context);
                listItem.SubItems.Add(notionItem.Source.Name);

                type = notionItem.GetType().Name;
                if (notionItem is Fact)
                    timestamp = ((Fact)notionItem).Date.ToShortDateString();
                else
                    timestamp = "";

                listItem.SubItems.Add(type);
                listItem.SubItems.Add(timestamp);

                resultsList.Items.Add(listItem);

                // Prevent entire collection being displayed
                displayCount++;
                if (displayCount >= displayLimit)
                    break;
            }

            // Refresh UI labels
            labelNumItems.Text = String.Format("Displaying {0} of {1} items", resultsList.Items.Count, searchResults.Count);
        }

        public void OpenFile(string memoryFile)
        {
            var openFileThread = new Thread(new ParameterizedThreadStart(OpenFileDoWork));
            openFileThread.Start(memoryFile);
        }

        public void OpenFileDoWork(object parameter)
        {
            MethodInvoker loadingFile = new MethodInvoker(MainForm_LoadingFile);
            MethodInvoker loadedFile = new MethodInvoker(MainForm_LoadedFile);

            Invoke(loadingFile);
            loadedMemory = new MemoryStore((string)parameter);
            Invoke(loadedFile);
        }

        void MainForm_LoadingFile()
        {
            workingLabelStatus.Text = "Loading file...";
            workingStatus.Visible = true;
            workingLabelProgress.Visible = true;

            workingStatus.Minimum = 0;
            workingStatus.Maximum = 100;
            workingStatus.Value = 0;

            loadingTimer.Interval = 100;
            loadingTimer.Tag = 0;
            loadingTimer.Start();
            this.Enabled = false;
        }

        void loadingTimer_Tick(object sender, EventArgs e)
        {
            if (workingStatus.Value < workingStatus.Maximum - 3)
                workingStatus.Value += 3;
            else
                workingStatus.Value = 0;

            var counter = (int)(loadingTimer.Tag);
            counter += 1;
            loadingTimer.Tag = counter;

            var seconds = (counter * loadingTimer.Interval) / 1000;

            workingLabelProgress.Text = seconds + " seconds passed";
        }

        void MainForm_LoadedFile()
        {
            var seconds = ((int)(loadingTimer.Tag) * loadingTimer.Interval) / 1000;

            workingLabelStatus.Text = String.Format("File loaded in {0} seconds", seconds);
            workingStatus.Visible = false;
            workingLabelProgress.Visible = false;

            loadingTimer.Stop();
            this.Enabled = true;

            // Refresh data
            comboSearchCollection.SelectedItem = "Notions";

            searchCollection = loadedMemory.Notions;
            searchResults = loadedMemory.Notions;

            create_ListItems();
        }

    }
}
